package com.jxpanda.infrastructure.core.tollkit.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.jxpanda.infrastructure.core.constant.DefaultValueConstant;
import com.jxpanda.infrastructure.core.constant.StringConstant;
import com.jxpanda.infrastructure.core.tollkit.ReflectionKit;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Consumer;

/**
 * @author Panda
 */
@Slf4j
public class NullSafeSerializer extends JsonSerializer<Object> {

    /**
     * null值的默认值序列化，当json对象中的值是null的时候，序列化默认值
     */
    private static final Map<Object, Consumer<JsonGenerator>> NULL_VALUE_DEFAULT_MAP = new HashMap<>() {{
        put(Collection.class, NullSafeSerializer::writeEmptyArray);
        put(List.class, NullSafeSerializer::writeEmptyArray);
        put(Set.class, NullSafeSerializer::writeEmptyArray);
        put(Map.class, NullSafeSerializer::writeEmptyObject);
        put(Enum.class, NullSafeSerializer::writeEmptyEnum);
        put(Object.class, NullSafeSerializer::writeEmptyObject);
        put(Byte.class, NullSafeSerializer::writeZero);
        put(Short.class, NullSafeSerializer::writeZero);
        put(Integer.class, NullSafeSerializer::writeZero);
        put(Long.class, NullSafeSerializer::writeZero);
        put(Float.class, NullSafeSerializer::writeDecimalZero);
        put(Double.class, NullSafeSerializer::writeDecimalZero);
        put(BigDecimal.class, NullSafeSerializer::writeDecimalZero);
        put(Boolean.class, NullSafeSerializer::writeBoolean);
        put(String.class, NullSafeSerializer::writeEmptyString);
        put(LocalDate.class, NullSafeSerializer::writeEmptyString);
        put(LocalTime.class, NullSafeSerializer::writeEmptyString);
        put(LocalDateTime.class, NullSafeSerializer::writeEmptyString);
    }};

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) {
        Object currentValue = gen.getOutputContext().getCurrentValue();
        String currentName = gen.getOutputContext().getCurrentName();
        Class<?> fieldType = ReflectionKit.getFieldType(currentValue.getClass(), currentName);
        if (fieldType != null && fieldType.isEnum()) {
            fieldType = Enum.class;
        }
        NULL_VALUE_DEFAULT_MAP.getOrDefault(fieldType, NullSafeSerializer::writeEmptyObject).accept(gen);
    }

    private static void writeEmptyArray(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeStartArray();
            jsonGenerator.writeEndArray();
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null array error");
        }
    }

    private static void writeEmptyObject(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeStartObject();
            jsonGenerator.writeEndObject();
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null object error");
        }
    }

    private static void writeEmptyString(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeString(StringConstant.BLANK);
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null string error");
        }
    }

    private static void writeEmptyEnum(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeString(StringConstant.UNKNOWN);
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null enum error");
        }
    }

    private static void writeZero(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeNumber(DefaultValueConstant.INTEGER);
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null number error");
        }
    }

    private static void writeDecimalZero(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeNumber(DefaultValueConstant.BIG_DECIMAL);
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null decimal error");
        }
    }

    private static void writeBoolean(JsonGenerator jsonGenerator) {
        try {
            jsonGenerator.writeBoolean(DefaultValueConstant.BOOLEAN);
        } catch (IOException e) {
            log.error("[Json Serializer Error] Null boolean error");
        }
    }

}